/*-+-*****************************************************************************
 Copyright (C) 2009-2012 Oceanside Software Corporation (R)
 Dallas, Texas

 Author       : Jason T. Brower
 Purpose      : This file is part of a point-of-sale software package
                originally written for Table-Service Restaurants.
              
 Date         : July 8th of 2012
              
 History      : The application that this software file belongs to was 
                written over a 3-Year period.  The first version was written
                in C# .Net 3.5 using Windows Forms.  Being new to .Net at
                the time, I soon learned of Windows Presentation Foundation,
                liked the graphics capabilities and databinding so I
                migrated to WPF.  When the .Net 4.0 framework was released
                the application was migrated from 3.5 to 4.0. Now today,
                .Net 4.5 RC is out and I was already in process of migrating
                before I made this public.
                
Excuse Me     : Please excuse the coding style, it is not representative of
                my typical work.  During the three years I was under a very
                tight budget, constantly running out of funding and was 
                working 18 hour days hyped up on 5-Hour Energy.  The 
                design is not textbook.  It is monolythic because of
                previous issues I will not get into.  There are few comments
                in the code and the ones that are there may be incorrect.
                
What it is not: This is not the exact version that I took through PA-DSS 2.0
                nor is it the exact version running at my customer sites.
                I removed some details for security purposes including some
                encryption algorithms.  The reporting was removed because
                I was including a third party library that cannot be 
                published with this Open Source.
                
What it is    : This application has been running at high volume restaraunts
                for over a year.  It never freezes, crashes or does anything
                unexpected.  So long as it is built, installed and configured
                correctly, it is a strong system that we can all enhance.

Contact       : Please note that I can no longer work for free.  However, you
                can reach me at information@oceansidesw.com.                                                      

*********************************************************************************/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Collections.ObjectModel;
using System.Data.Objects.DataClasses;
using System.Data.Objects;

#if _LOCALDB
  using Oceanside.LocalDB;
#else
using Oceanside.RemoteDB;
#endif

#if _LOCALDB
  namespace Oceanside.LocalDB
#else
namespace Oceanside.RemoteDB
#endif
{
    /// <summary>
    /// Keeps track of each seating area in the restaurant.
    /// </summary>
    public partial class SHIFT : INotifyPropertyChanged
    {
        public SHIFT()
        {

        }

        public delegate void BindCheckoutsCallbackType(List<SHIFT> checkouts);

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public static void GetCheckShifts(int takeCount, BindCheckoutsCallbackType callback)
        {
            List<SHIFT> runList = null;
            try
            {
                using (DominicaEntities context = new DominicaEntities(DominicaEntities.GetEfConString()))
                {
                    var q = from shift in context.SHIFTS.Include("TIMESLIP").Where(s => s.IsComplete && s.TIMESLIP != null)
                            orderby shift.TIMESLIP.ClockedOut descending
                            select shift;
                    if (q.Any())
                    {
                        runList = q.Take(takeCount).ToList();
                    }
                }
            }
            catch (Exception e)
            {
                Constants.ErrorDispatcher.Notify(Error.EType.E_REPORT_ERROR, e);
            }
            finally
            {
                try
                {
                    PosWindow.MainPosWindow.Dispatcher.Invoke(callback, runList);
                }
                catch (Exception e)
                {
                    Logging.LogException(e);
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool UserCanOrder()
        {
            bool answer = false;
            try
            {
                if (this.TIMESLIP != null)
                {
                    var q = from ROLE in GlobalContext.ROLES
                            where ROLE.Id == this.TIMESLIP.RoleId &&
                                ROLE.IsDeleted == false &&
                                ROLE.ACCESS_LEVEL.IsDeleted == false &&
                                ROLE.ACCESS_LEVEL.CanOrder == true
                            select ROLE;

                    answer = q.Any() || UserIsManager();
                }
            }
            catch (Exception e)
            {
                Logging.LogException(e);
            }
            return answer;
        }
        /// <summary>
        /// 
        /// </summary>
        public void Lock()
        {
            LastKioskId = KIOSK.Get(SHIFT.GlobalContext).Id;
            IsLocked = true;
            SHIFT.GlobalContext.SaveChanges();
        }

        public static SHIFT GetNow(DominicaEntities context, BUSINESS_DAY bd, USER user)
        {
            SHIFT shift = null;
            try
            {
                var q = from s in context.SHIFTS
                        where (s.IsComplete == false) &&
                        s.NavBusinessDayId == bd.Id &&
                        s.UserId == user.Id
                        select s;

                if (q.Any())
                {
                    shift = q.First();
                }

                if (shift == null)
                {
                    shift = new SHIFT();
                    shift.LastKioskId = KIOSK.Get(SHIFT.GlobalContext).Id;
                    shift.IsLocked = false;
                    shift.NavBusinessDayId = bd.Id;
                    shift.UserId = user.Id;
                    shift.DateStamp = DateTime.Now;
                    context.SHIFTS.AddObject(shift);
                    context.SaveChanges();
                }
            }
            catch (Exception e)
            {
                Logging.LogException(e);
            }
            return shift;
        }

        public static void InitGlobalContext()
        {
            if (_globalContext != null)
            {
                _globalContext.Dispose();
            }
            _globalContext = new DominicaEntities(DominicaEntities.GetEfConString());
            MENU.CacheCurrentMenuInstance();
        }

        public static void SetContextToNoTracking()
        {
            GlobalContext.ACCESS_LEVELS.MergeOption = MergeOption.NoTracking;
            GlobalContext.AUTO_GRATUITYS.MergeOption = MergeOption.NoTracking;
            GlobalContext.COMP_ACCOUNTS.MergeOption = MergeOption.NoTracking;
            GlobalContext.DAYPARTS.MergeOption = MergeOption.NoTracking;
            GlobalContext.EXCEPTION_MODIFIER_GROUPS.MergeOption = MergeOption.NoTracking;
            GlobalContext.EXCEPTION_MODIFIERS.MergeOption = MergeOption.NoTracking;
            GlobalContext.EXCLUSIVE_TAXRATES.MergeOption = MergeOption.NoTracking;
            GlobalContext.FINGERPASSWORDS.MergeOption = MergeOption.NoTracking;
            GlobalContext.FORCED_MODIFIER_GROUPS.MergeOption = MergeOption.NoTracking;
            GlobalContext.FORCED_MODIFIERS.MergeOption = MergeOption.NoTracking;
            GlobalContext.GLCODES.MergeOption = MergeOption.NoTracking;
            GlobalContext.HOUSE_ACCOUNTS.MergeOption = MergeOption.NoTracking;
            GlobalContext.INCLUSIVE_TAXRATES.MergeOption = MergeOption.NoTracking;
            GlobalContext.INCLUSIVE_TIPRATES.MergeOption = MergeOption.NoTracking;
            GlobalContext.INVENTORY_COUNT_LOGS.MergeOption = MergeOption.NoTracking;
            GlobalContext.INVOICE_LINE_ITEMS.MergeOption = MergeOption.NoTracking;
            GlobalContext.JOB_CODES.MergeOption = MergeOption.NoTracking;
            GlobalContext.KIOSKS.MergeOption = MergeOption.NoTracking;
            GlobalContext.LOCATION_LAYOUTS.MergeOption = MergeOption.NoTracking;
            GlobalContext.MAP_KIOSK_PRODUCT_GROUP_AND_PRINTER_GROUPS.MergeOption = MergeOption.NoTracking;
            GlobalContext.MENU_GROUPS.MergeOption = MergeOption.NoTracking;
            GlobalContext.MENUS.MergeOption = MergeOption.NoTracking;
            GlobalContext.PAGELAYOUTS.MergeOption = MergeOption.NoTracking;
            GlobalContext.LAYOUTOBJS.MergeOption = MergeOption.NoTracking;
            GlobalContext.PAYGRADES.MergeOption = MergeOption.NoTracking;
            GlobalContext.PAYMENT_REASONS.MergeOption = MergeOption.NoTracking;
            GlobalContext.PRICE_INTERVAL_DISCOUNTS.MergeOption = MergeOption.NoTracking;
            GlobalContext.PRINTER_GROUPS.MergeOption = MergeOption.NoTracking;
            GlobalContext.PRINTERS.MergeOption = MergeOption.NoTracking;
            GlobalContext.PROCESSORS.MergeOption = MergeOption.NoTracking;
            GlobalContext.PRODUCT_GROUPS.MergeOption = MergeOption.NoTracking;
            GlobalContext.PRODUCTS.MergeOption = MergeOption.NoTracking;
            GlobalContext.RECIPE_INGREDIENTS.MergeOption = MergeOption.NoTracking;
            GlobalContext.RECIPE_PRODUCTS.MergeOption = MergeOption.NoTracking;
            GlobalContext.RECIPES.MergeOption = MergeOption.NoTracking;
            GlobalContext.REVENUE_CENTERS.MergeOption = MergeOption.NoTracking;
            GlobalContext.REVENUE_TYPES.MergeOption = MergeOption.NoTracking;
            GlobalContext.ROLES.MergeOption = MergeOption.NoTracking;
            GlobalContext.SURCHARGE_ACCOUNTS.MergeOption = MergeOption.NoTracking;
            GlobalContext.USERS.MergeOption = MergeOption.NoTracking;
            GlobalContext.VENDOR_ACCOUNTS.MergeOption = MergeOption.NoTracking;
            GlobalContext.WORK_CENTERS.MergeOption = MergeOption.NoTracking;
        }

        public static void SetContextToAppendOnly()
        {
            GlobalContext.ACCESS_LEVELS.MergeOption = MergeOption.AppendOnly;
            GlobalContext.AUTO_GRATUITYS.MergeOption = MergeOption.AppendOnly;
            GlobalContext.COMP_ACCOUNTS.MergeOption = MergeOption.AppendOnly;
            GlobalContext.DAYPARTS.MergeOption = MergeOption.AppendOnly;
            GlobalContext.EXCEPTION_MODIFIER_GROUPS.MergeOption = MergeOption.AppendOnly;
            GlobalContext.EXCEPTION_MODIFIERS.MergeOption = MergeOption.AppendOnly;
            GlobalContext.EXCLUSIVE_TAXRATES.MergeOption = MergeOption.AppendOnly;
            GlobalContext.FINGERPASSWORDS.MergeOption = MergeOption.AppendOnly;
            GlobalContext.FORCED_MODIFIER_GROUPS.MergeOption = MergeOption.AppendOnly;
            GlobalContext.FORCED_MODIFIERS.MergeOption = MergeOption.AppendOnly;
            GlobalContext.GLCODES.MergeOption = MergeOption.AppendOnly;
            GlobalContext.HOUSE_ACCOUNTS.MergeOption = MergeOption.AppendOnly;
            GlobalContext.INCLUSIVE_TAXRATES.MergeOption = MergeOption.AppendOnly;
            GlobalContext.INCLUSIVE_TIPRATES.MergeOption = MergeOption.AppendOnly;
            GlobalContext.INVENTORY_COUNT_LOGS.MergeOption = MergeOption.AppendOnly;
            GlobalContext.INVOICE_LINE_ITEMS.MergeOption = MergeOption.AppendOnly;
            GlobalContext.JOB_CODES.MergeOption = MergeOption.AppendOnly;
            GlobalContext.KIOSKS.MergeOption = MergeOption.AppendOnly;
            GlobalContext.LOCATION_LAYOUTS.MergeOption = MergeOption.AppendOnly;
            GlobalContext.MAP_KIOSK_PRODUCT_GROUP_AND_PRINTER_GROUPS.MergeOption = MergeOption.AppendOnly;
            GlobalContext.MENU_GROUPS.MergeOption = MergeOption.AppendOnly;
            GlobalContext.MENUS.MergeOption = MergeOption.AppendOnly;
            GlobalContext.PAGELAYOUTS.MergeOption = MergeOption.AppendOnly;
            GlobalContext.LAYOUTOBJS.MergeOption = MergeOption.AppendOnly;
            GlobalContext.PAYGRADES.MergeOption = MergeOption.AppendOnly;
            GlobalContext.PAYMENT_REASONS.MergeOption = MergeOption.AppendOnly;
            GlobalContext.PRICE_INTERVAL_DISCOUNTS.MergeOption = MergeOption.AppendOnly;
            GlobalContext.PRINTER_GROUPS.MergeOption = MergeOption.AppendOnly;
            GlobalContext.PRINTERS.MergeOption = MergeOption.AppendOnly;
            GlobalContext.PROCESSORS.MergeOption = MergeOption.AppendOnly;
            GlobalContext.PRODUCT_GROUPS.MergeOption = MergeOption.AppendOnly;
            GlobalContext.PRODUCTS.MergeOption = MergeOption.AppendOnly;
            GlobalContext.RECIPE_INGREDIENTS.MergeOption = MergeOption.AppendOnly;
            GlobalContext.RECIPE_PRODUCTS.MergeOption = MergeOption.AppendOnly;
            GlobalContext.RECIPES.MergeOption = MergeOption.AppendOnly;
            GlobalContext.REVENUE_CENTERS.MergeOption = MergeOption.AppendOnly;
            GlobalContext.REVENUE_TYPES.MergeOption = MergeOption.AppendOnly;
            GlobalContext.ROLES.MergeOption = MergeOption.AppendOnly;
            GlobalContext.SURCHARGE_ACCOUNTS.MergeOption = MergeOption.AppendOnly;
            GlobalContext.USERS.MergeOption = MergeOption.AppendOnly;
            GlobalContext.VENDOR_ACCOUNTS.MergeOption = MergeOption.AppendOnly;
            GlobalContext.WORK_CENTERS.MergeOption = MergeOption.AppendOnly;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="session"></param>
        public void SwitchToMyScreen()
        {
            try
            {
                if (IsClockedIn && !IsOnBreak && UserCanOrder())
                {
                    if (Constants.IsQuickServiceMode)
                    {
                        int DONTCARE = 0;
                        ///Add a new table
                        ORDER o = SHIFT.Current.AddTable(DONTCARE, SHIFT.Current.User, false);
                        POBindings.TableDisplayString = "Order " + o.TableInt;
                        OrderApi.Show();
                        PosWindow.WindowBeforeLock = null;
                    }
                    else
                    {
                        ControlPanelWindow.Show();
                    }
                }
                else
                {
                    TimeSheetWindow.Show();
                }
            }
            catch (Exception exc)
            {
                Constants.ErrorDispatcher.Notify(Error.EType.E_TSBIND_EXIT_BUTTON_CLICK, exc);
            }
        }

        public static SHIFT _current;
        public static SHIFT Current
        {
            get { return _current; }
            set
            {
                _current = value;
                CloseCheck.GlobalStateObject.Refresh();
            }
        }

        private static DominicaEntities _globalContext;
        public static DominicaEntities GlobalContext
        {
            get
            {
                if (_globalContext == null ||
                    _globalContext.Connection.State == System.Data.ConnectionState.Broken)
                {
                    if (_globalContext.Connection.State == System.Data.ConnectionState.Broken)
                    {
                        Logging.LogMessage("The object context was broken.");
                        UMD.ShowGuiMessageSTASafe_NOTHROW("The network connection to the server was broken.  Click [OK] to re-establish the connection.");
                    }
                    InitGlobalContext();
                }
                return _globalContext;
            }
            set { _globalContext = value; }
        }

        public USER User
        {
            get
            {
                USER user = null;
                try
                {
                    user =
                        GlobalContext.USERS.Where(u => u.Id == this.UserId && u.IsTerminated == false).FirstOrDefault();
                }
                catch (Exception e)
                {
                    Logging.LogException(e);
                }
                return user;
            }
        }

        public ROLE Role
        {
            get
            {
                ROLE role = null;
                if (this.TIMESLIP != null)
                {
                    role = GlobalContext.ROLES.
                        Where(r => this.TIMESLIP.RoleId == r.Id).FirstOrDefault();
                }
                return role;
            }
        }

        public TIMESLIP TimePunch
        {
            get
            {
                return this.TIMESLIP;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public enum DrawerOwnershipEnum
        {
            NoDrawer,
            Drawer1,
            Drawer2,
            BothDrawers
        }

        /// <summary>
        /// As a session is in progress, this holds the currently selected table that the user is viewing
        /// or modifying.
        /// </summary>
        [NonSerialized]
        private static ORDER selectedOrder;
        public static ORDER SelectedOrder
        {
            get { return SHIFT.selectedOrder; }
            set { SHIFT.selectedOrder = value; }
        }

        public Boolean IsClockedOut
        {
            get { return !IsClockedIn; }
        }


        [field: NonSerialized]
        public new event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            try
            {
                PropertyChangedEventHandler handler = PropertyChanged;
                if (handler != null)
                {
                    handler(this, e);
                }
            }
            catch (Exception excep)
            {
                Constants.ErrorDispatcher.Notify(Error.EType.E_PLACEHOLDER, excep);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool UserIsBarTender()
        {
            var q = from ROLE in GlobalContext.ROLES
                    where ROLE.Id == this.TIMESLIP.RoleId &&
                        ROLE.JOB_CODE.IsBarTender == true
                    select ROLE;

            return q.Any();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool UserIsDeliveryDriver()
        {
            var q = from ROLE in GlobalContext.ROLES
                    where ROLE.Id == this.TIMESLIP.RoleId &&
                        ROLE.JOB_CODE.IsDeliveryDriver == true
                    select ROLE;

            return q.Any();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool UserIsHost()
        {
            var q = from ROLE in GlobalContext.ROLES
                    where ROLE.Id == this.TIMESLIP.RoleId &&
                        ROLE.JOB_CODE.IsHost == true
                    select ROLE;

            return q.Any();
        }


        /// <summary>
        /// This is used to decide if we need to show the release drawer button in case an employee left it open.
        /// </summary>
        public bool UserIsManager()
        {
            if (this.TIMESLIP != null)
            {
                try
                {
                    var q = from ROLE in GlobalContext.ROLES
                            where ROLE.Id == this.TIMESLIP.RoleId &&
                                ROLE.JOB_CODE.IsManager == true
                            select ROLE;

                    return q.Any() || PosWindow.ManagerCardWasSwiped;
                }
                catch (Exception e)
                {
                    Logging.LogException(e);
                }
            }
            return false;
        }

        /// <summary>
        /// This is used to decide if we need to show the release drawer button in case an employee left it open.
        /// </summary>
        public bool UserIsCook()
        {
            var q = from ROLE in GlobalContext.ROLES
                    where ROLE.Id == this.TIMESLIP.RoleId &&
                       ROLE.JOB_CODE.IsCook == true
                    select ROLE;

            return q.Any();
        }

        /// <summary>
        /// This is used to decide if we need to show the release drawer button in case an employee left it open.
        /// </summary>
        public bool UserIsRetail()
        {
            var q = from ROLE in GlobalContext.ROLES
                    where ROLE.Id == this.TIMESLIP.RoleId &&
                       ROLE.JOB_CODE.IsRetail == true
                    select ROLE;

            return q.Any();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool UserIsWaiter()
        {
            var q = from ROLE in GlobalContext.ROLES
                    where ROLE.Id == this.TIMESLIP.RoleId &&
                        ROLE.JOB_CODE.IsWaiter == true
                    select ROLE;

            return q.Any();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool UserIsValet()
        {
            var q = from ROLE in GlobalContext.ROLES
                    where ROLE.Id == this.TIMESLIP.RoleId &&
                        ROLE.JOB_CODE.IsValet == true
                    select ROLE;

            return q.Any();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool UserCanViewReports()
        {
            var q = from ROLE in GlobalContext.ROLES
                    where ROLE.Id == this.TIMESLIP.RoleId &&
                       ROLE.ACCESS_LEVEL.CanViewReports == true
                    select ROLE;

            return q.Any() || PosWindow.ManagerCardWasSwiped || UserIsManager();
        }

        public bool UserCanPayIn()
        {
            if (GlobalContext != null)
            {
                return PosWindow.ManagerCardWasSwiped || this.Role != null && this.Role.ACCESS_LEVEL.CanPayIn;
            }
            else
            {
                return false;
            }
        }

        public bool UserCanPayOut()
        {
            if (GlobalContext != null)
            {
                return PosWindow.ManagerCardWasSwiped || this.Role != null && this.Role.ACCESS_LEVEL != null
                    && this.Role.ACCESS_LEVEL.CanPayOut;
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool UserCanCompItem()
        {
            var q = from ROLE in GlobalContext.ROLES
                    where ROLE.Id == this.TIMESLIP.RoleId &&
                       ROLE.ACCESS_LEVEL.CanApplyCompToItem == true
                    select ROLE;

            return q.Any() || PosWindow.ManagerCardWasSwiped || UserIsManager();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool UserCanVoidItem()
        {
            var q = from ROLE in GlobalContext.ROLES
                    where ROLE.Id == this.TIMESLIP.RoleId &&
                        ROLE.ACCESS_LEVEL.CanApplyVoidToItem == true
                    select ROLE;

            return q.Any() || PosWindow.ManagerCardWasSwiped || UserIsManager();
        }

        public bool UserCanVoidPayment()
        {
            var q = from ROLE in GlobalContext.ROLES
                    where ROLE.Id == this.TIMESLIP.RoleId &&
                        ROLE.ACCESS_LEVEL.CanVoidPayment == true
                    select ROLE;

            return q.Any() || PosWindow.ManagerCardWasSwiped || UserIsManager();
        }

        public bool UserCanApplyHousePayment()
        {
            var q = from ROLE in GlobalContext.ROLES
                    where ROLE.Id == this.TIMESLIP.RoleId &&
                        ROLE.ACCESS_LEVEL.CanApplyHousePayment == true
                    select ROLE;

            return q.Any() || PosWindow.ManagerCardWasSwiped || UserIsManager();
        }

        public bool UserCanPromo()
        {
            var q = from ROLE in GlobalContext.ROLES
                    where ROLE.Id == this.TIMESLIP.RoleId &&
                        ROLE.ACCESS_LEVEL.CanPromoCheck == true
                    select ROLE;

            return q.Any() || PosWindow.ManagerCardWasSwiped || UserIsManager();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool UserCanCloseHouse()
        {
            var q = from ROLE in GlobalContext.ROLES
                    where ROLE.Id == this.TIMESLIP.RoleId &&
                        ROLE.ACCESS_LEVEL.CanCloseHouse == true
                    select ROLE;

            return q.Any() || PosWindow.ManagerCardWasSwiped || UserIsManager();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool UserCanTransferCheck()
        {
            var q = from ROLE in GlobalContext.ROLES
                    where ROLE.Id == this.TIMESLIP.RoleId &&
                        ROLE.ACCESS_LEVEL.CanTransferOrder == true
                    select ROLE;

            return q.Any() || PosWindow.ManagerCardWasSwiped || UserIsManager();
        }


        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool UserCanAccessSystemConfig()
        {
            var q = from ROLE in GlobalContext.ROLES
                    where ROLE.Id == this.TIMESLIP.RoleId &&
                       ROLE.ACCESS_LEVEL.CanAccessSystemConfig == true
                    select ROLE;

            return q.Any() || UserIsManager();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool UserCanSeeOtherUsersOrders()
        {
            var q = from ROLE in GlobalContext.ROLES
                    where ROLE.Id == this.TIMESLIP.RoleId &&
                        ROLE.ACCESS_LEVEL.CanSeeOtherUsersOrders == true
                    select ROLE;

            return q.Any() || UserIsManager();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool UserCanReopenOrders()
        {
            var q = from ROLE in GlobalContext.ROLES
                    where ROLE.Id == this.TIMESLIP.RoleId &&
                        ROLE.ACCESS_LEVEL.CanReopenOrder == true
                    select ROLE;

            return q.Any() || UserIsManager();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool UserCanSetMagStripe()
        {
            var q = from ROLE in GlobalContext.ROLES
                    where ROLE.Id == this.TIMESLIP.RoleId &&
                        ROLE.ACCESS_LEVEL.CanSetMagStripe == true
                    select ROLE;

            return q.Any() || UserIsManager();
        }


        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool UserCanSearchAllPayments()
        {
            var q = from ROLE in GlobalContext.ROLES
                    where ROLE.Id == this.TIMESLIP.RoleId
                    && ROLE.ACCESS_LEVEL.CanSearchAllPayments == true
                    select ROLE;

            return q.Any() || PosWindow.ManagerCardWasSwiped || UserIsManager();
        }


        public bool UserCanNoSale()
        {
            var q = from ROLE in GlobalContext.ROLES
                    where ROLE.Id == this.TIMESLIP.RoleId
                    && ROLE.ACCESS_LEVEL.CanNoSale == true
                    select ROLE;

            return q.Any() || PosWindow.ManagerCardWasSwiped || UserIsManager();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="drawer"></param>
        /// <returns></returns>
        public static bool DrawerIsOwned(SHIFT.DrawerOwnershipEnum drawer)
        {
            try
            {
                BUSINESS_DAY bd = BUSINESS_DAY.GetNow(GlobalContext);
                var q1 = from shift in bd.SHIFTS
                         where (shift.TimePunch == null || shift.TimePunch.ClockedOut == null) && ((shift.MyDrawerOwnershipStatus == (int)drawer && shift.MyDrawerOwnerTermId == KIOSK.Get(SHIFT.GlobalContext).Id) ||
                         (shift.MyDrawerOwnershipStatus == (int)SHIFT.DrawerOwnershipEnum.BothDrawers &&
                         shift.MyDrawerOwnerTermId == KIOSK.Get(SHIFT.GlobalContext).Id))
                         select shift;
                return q1.Any();
            }
            catch (Exception e)
            {
                Logging.LogException(e);
            }
            return false;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="drawer"></param>
        /// <returns></returns>
        public static SHIFT GetDrawerOwnerSession(SHIFT.DrawerOwnershipEnum drawer)
        {
            try
            {
                BUSINESS_DAY bd = BUSINESS_DAY.GetNow(GlobalContext);
                var q1 = from shift in bd.SHIFTS
                         where (shift.TimePunch == null || shift.TimePunch.ClockedOut == null) && ((shift.MyDrawerOwnershipStatus == (int)drawer && shift.MyDrawerOwnerTermId == KIOSK.Get(SHIFT.GlobalContext).Id) ||
                         (shift.MyDrawerOwnershipStatus == (int)DrawerOwnershipEnum.BothDrawers && shift.MyDrawerOwnerTermId == KIOSK.Get(SHIFT.GlobalContext).Id))
                         select shift;
                if (q1.Count() != 0)
                {
                    SHIFT sess = q1.First();
                    return sess;
                }
            }
            catch (Exception e)
            {
                Logging.LogException(e);
            }
            return null;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool IsDrawerOwner(DrawerOwnershipEnum drawerNumber = DrawerOwnershipEnum.NoDrawer)
        {
            return MyDrawerOwnershipStatus == (int)drawerNumber;
        }

        /// <summary>
        /// 
        /// </summary>
        public void AddAsDrawerOwner(DrawerOwnershipEnum drawer)
        {
            if (MyDrawerOwnershipStatus != (int)DrawerOwnershipEnum.NoDrawer && MyDrawerOwnerTermId == KIOSK.Get(SHIFT.GlobalContext).Id)
            {
                MyDrawerOwnershipStatus = (int)DrawerOwnershipEnum.BothDrawers;
                MyDrawerOwnerTermId = KIOSK.Get(SHIFT.GlobalContext).Id;
            }
            else
            {
                MyDrawerOwnershipStatus = (int)drawer;
                MyDrawerOwnerTermId = KIOSK.Get(SHIFT.GlobalContext).Id;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public static void RemoveAsDrawerOwner(DrawerOwnershipEnum drawer)
        {
            try
            {
                SHIFT session = GetDrawerOwnerSession(drawer);
                Int64 kId = KIOSK.Get(SHIFT.GlobalContext).Id;
                if (session != null)
                {
                    if (session.MyDrawerOwnershipStatus == (int)drawer && session.MyDrawerOwnerTermId == kId)
                    {
                        session.MyDrawerOwnershipStatus = (int)DrawerOwnershipEnum.NoDrawer;
                        session.MyDrawerOwnerTermId = 0;
                    }
                    else if (session.MyDrawerOwnershipStatus == (int)DrawerOwnershipEnum.BothDrawers && session.MyDrawerOwnerTermId == kId)
                    {
                        if (drawer == DrawerOwnershipEnum.Drawer1)
                        {
                            session.MyDrawerOwnershipStatus = (int)DrawerOwnershipEnum.Drawer2;
                        }
                        else
                        {
                            session.MyDrawerOwnershipStatus = (int)DrawerOwnershipEnum.Drawer1;
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Logging.LogException(e);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="tableNum"></param>
        /// <param name="user"></param>
        /// <param name="isBarSeatMode"></param>
        public ORDER AddTable(int tableNum, USER user, bool isBarSeatMode = false, int seatCount = 1)
        {
            ORDER order = new ORDER(tableNum, user, isBarSeatMode, seatCount);
            SHIFT.Current.ORDERS.Add(order);
            SelectedOrder = order;
            SHIFT.GlobalContext.SaveChanges();

            ///If this is quick service mode, then we need to make the 
            ///table int and name the order ID.  Notice that IF we ever
            ///overflow a 32-bit integer then it will roll on us because
            ///we are casting down to an int from 64 bit.
            if (Constants.IsQuickServiceMode)
            {
                BUSINESS_DAY bd = BUSINESS_DAY.GetNow(GlobalContext);
                int ordersToday = bd.SHIFTS.Select(s => s.ORDERS).Sum(s => s.Count);
                order.TableInt = ordersToday;
                order.TableName = order.TableInt.ToString();
                SHIFT.GlobalContext.SaveChanges();
            }
            return order;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="orderNum"></param>
        /// <param name="orders"></param>
        /// <returns></returns>
        public bool CheckTableAvailibility(
            int orderNum,
            bool isBarSeatMode)
        {
            if (isBarSeatMode)
            {
                return ORDERS.Where(o => o.TableInt == orderNum && !o.IsClosed && o.IsBarSeat).Count() == 0;
            }
            else
            {
                return ORDERS.Where(o => o.TableInt == orderNum && !o.IsClosed && !o.IsBarSeat).Count() == 0;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="tbl"></param>
        public static void RemoveOrder(ORDER tbl)
        {
            GlobalContext.SaveChanges();
            foreach (SALE s in tbl.SALES.ToList())
            {
                s.TryDeleteAllCountPendingSale();
            }

            tbl.NOSALES.Clear();

            SHIFT.Current.ORDERS.Remove(tbl);
            GlobalContext.ORDERS.DeleteObject(tbl);
            GlobalContext.SaveChanges();
        }
        public class SALES_BY_REVTYPE
        {
            public Int64 rtId;
            public string rtName;
            public decimal total;
        }
        public class COMPS_BY_COMPTYPE
        {
            public Int64 ctId;
            public string ctName;
            public decimal total;
        }
        public class VOIDS_BY_VOIDTYPE
        {
            public Int64 vtId;
            public string vtName;
            public decimal total;
        }
        public class PROMOS_BY_PROMOTYPE
        {
            public Int64 ptId;
            public string ptName;
            public decimal total;
        }
        public class INCLUSIVE_TAX_BY_TAXTYPE
        {
            public Int64 tId;
            public string name;
            public decimal incTax;
            public decimal grossSales;
            public decimal netSales;
        }
        public class TRANSACTIONS_BY_TRANSACTION_TYPE
        {
            public Int64 tTypeId;
            public string name;
            public decimal total;
        }

        public class PAIDIN_BY_TYPE
        {
            public Int64 reasonId;
            public string name;
            public decimal total;
        }

        public class PAIDOUT_BY_TYPE
        {
            public Int64 reasonId;
            public string name;
            public decimal total;
        }

        public class HOUSE_ACCOUNT_BY_TYPE
        {
            public Int64 accountId;
            public string name;
            public decimal total;
        }

        public class VOUCHERS_BY_VOUCHERTYPE
        {
            public Int64 reasonId;
            public string name;
            public decimal total;
        }

        public class SHIFT_CHECKOUTDATA
        {
            public int plateCount = 0;
            public bool isHouseCloseout = false;

            /// <summary>
            /// Employee Information.
            /// </summary>
            public SHIFT shift;
            public BUSINESS_DAY businessDay;
            public USER user;
            public DAYPART clockedInDp;
            public DAYPART clockedOutDp;
            public REVENUE_CENTER revCenter;
            public ROLE role;

            /// <summary>
            /// Sales information.
            /// </summary>
            public List<SALES_BY_REVTYPE> salesGroupByRevType = new List<SALES_BY_REVTYPE>();
            public decimal totalSales = 0M;

            /// <summary>
            /// Comp information.
            /// </summary>
            public List<COMPS_BY_COMPTYPE> salesGroupByCompType = new List<COMPS_BY_COMPTYPE>();
            public decimal totalComps = 0M;

            /// <summary>
            /// Void Information.
            /// </summary>
            public List<VOIDS_BY_VOIDTYPE> salesGroupByVoidType = new List<VOIDS_BY_VOIDTYPE>();
            public decimal totalVoids = 0M;

            /// <summary>
            /// Promo Information.
            /// </summary>
            public List<PROMOS_BY_PROMOTYPE> salesGroupByPromoType = new List<PROMOS_BY_PROMOTYPE>();
            public decimal totalPromo = 0M;

            /// <summary>
            /// Total Paid in
            /// </summary>
            public List<PAIDIN_BY_TYPE> paidInByType = new List<PAIDIN_BY_TYPE>();
            public decimal totalPaidIn = 0M;

            /// <summary>
            /// How much cash were the drawers loaded with today?
            /// </summary>
            public decimal dayCashStart = 0M;

            /// <summary>
            /// Total Paid Out
            /// </summary>
            public List<PAIDOUT_BY_TYPE> paidOutByType = new List<PAIDOUT_BY_TYPE>();
            public decimal totalPaidOut = 0M;

            public List<HOUSE_ACCOUNT_BY_TYPE> houseAccountByType = new List<HOUSE_ACCOUNT_BY_TYPE>();
            public decimal houseTransactionsTotal = 0M;
            /// <summary>
            /// Dollars in giftcards sold.
            /// </summary>
            public decimal giftCardAmountSold = 0M;

            /// <summary>
            /// Exclusive Taxes
            /// </summary>
            public decimal totalExclusiveTaxes = 0M;
            public decimal exclusivelyTaxableSales = 0M;

            /// <summary>
            /// Inclusive Taxes
            /// </summary>
            public List<INCLUSIVE_TAX_BY_TAXTYPE> salesGroupByInclusiveType = new List<INCLUSIVE_TAX_BY_TAXTYPE>();
            public decimal totalInclusiveTaxes = 0M;
            public decimal inclusivelyTaxableSales = 0M;

            /// <summary>
            /// Save the ids of the transactions for printing.
            /// </summary>
            public List<Int64> ccTransactionIds = new List<Int64>();
            public List<Int64> gcTransactionIds = new List<Int64>();
            public List<TRANSACTION> transactionsByAnotherUser = new List<TRANSACTION>();

            public decimal paymentTotal = 0M;
            public decimal creditCardTipTotal = 0M;
            public decimal creditTransactionTotal = 0M;
            public decimal giftCardTransTotal = 0M;
            public decimal giftCardTipTotal = 0M;
            public decimal voucherTransactionTotal = 0M;
            public decimal autoGratuityTotal = 0M;

            List<VOUCHERS_BY_VOUCHERTYPE> vouchersByVoucherType = new List<VOUCHERS_BY_VOUCHERTYPE>();

            /// <summary>
            /// All transactions grouped by type.
            /// </summary>
            public List<TRANSACTIONS_BY_TRANSACTION_TYPE> transactionsByTypeList = new List<TRANSACTIONS_BY_TRANSACTION_TYPE>();

            public decimal TotalDiscounts
            {
                get
                {
                    return totalComps + totalPromo + totalVoids;
                }
            }

            public decimal TotalChecks
            {
                get
                {
                    try
                    {
                        var q = transactionsByTypeList.Where(t => t.tTypeId == TRANSACTION.CONST_PAY_CHECK);
                        if (q.Any())
                        {
                            return q.Sum(t => t.total);
                        }
                        else
                        {
                            return 0;
                        }
                    }
                    catch (Exception ex)
                    {
                        Logging.LogException(ex);
                    }
                    return 0;
                }
            }

            public decimal TotalCash
            {
                get
                {
                    return TotalDue - TotalChecks;
                }
            }

            /// <summary>
            /// The cash due by the employee.
            /// </summary>
            public decimal TotalDue
            {
                get
                {
                    if (isHouseCloseout)
                    {
                        return
                        dayCashStart +
                        totalSales +
                        totalExclusiveTaxes +
                        totalPaidIn -
                        totalPaidOut -
                        TotalDiscounts -
                        creditTransactionTotal -
                        giftCardTransTotal -
                        creditCardTipTotal -
                        giftCardTipTotal -
                        houseTransactionsTotal;
                    }
                    else
                    {
                        return
                        totalSales +
                        totalExclusiveTaxes +
                        totalPaidIn +
                        shift.DrawerStart -
                        totalPaidOut -
                        TotalDiscounts -
                        creditTransactionTotal -
                        giftCardTransTotal -
                        creditCardTipTotal -
                        giftCardTipTotal -
                        houseTransactionsTotal;
                    }
                }
            }
        }

        public static void CloseShift(DominicaEntities context, SHIFT shift, decimal claimedCashTips, bool wasAutoClocked)
        {
            if (shift.TIMESLIP != null)
            {
                shift.TIMESLIP.ClockedOut = DateTime.Now;
                shift.IsClockedIn = false;
                shift.IsOnBreak = false;
                shift.IsComplete = true;
                shift.TIMESLIP.CashTipsClaimed = claimedCashTips;
                shift.TIMESLIP.WasAutoClockedOut = wasAutoClocked;
                shift.TIMESLIP.ClockedOutDaypartId = DAYPART.GetCurrDaypart(context).Id;
                shift.TIMESLIP.ClockedOutKioskId = KIOSK.Get(SHIFT.GlobalContext).Id;
                shift.MyDrawerOwnershipStatus = (int)SHIFT.DrawerOwnershipEnum.NoDrawer;
                shift.MyDrawerOwnerTermId = null;
                context.SaveChanges();
            }
        }
        public static SHIFT_CHECKOUTDATA GenerateCheckoutData(SHIFT shift, DominicaEntities context, bool isHouseCheckout)
        {
            return GenerateCheckoutData(new List<SHIFT> { shift }, context, isHouseCheckout);
        }

        public static SHIFT_CHECKOUTDATA GenerateCheckoutData(List<SHIFT> shifts, DominicaEntities context, bool isHouseCheckout)
        {
            SHIFT_CHECKOUTDATA scd = new SHIFT_CHECKOUTDATA();

            try
            {
                scd.isHouseCloseout = isHouseCheckout;
                scd.autoGratuityTotal = CommonCalls.GetAutoGratuity(shifts);
                scd.shift = shifts.FirstOrDefault();
                if (isHouseCheckout && scd.businessDay == null)
                {
                    scd.businessDay = scd.shift.BUSINESS_DAY;
                }
                if (scd.shift != null && scd.shift.TIMESLIP != null)
                {
                    scd.user = USER.GetUserById(scd.shift.UserId);

                    scd.clockedInDp =
                        context.DAYPARTS.Where(dp => dp.Id == scd.shift.TIMESLIP.ClockedInDaypartId).FirstOrDefault();

                    scd.clockedOutDp =
                        context.DAYPARTS.Where(dp => dp.Id == scd.shift.TIMESLIP.ClockedOutDaypartId).FirstOrDefault();

                    scd.revCenter =
                        context.REVENUE_CENTERS.Where(rc => rc.Id == scd.shift.TIMESLIP.RevenueCenterId).FirstOrDefault();

                    scd.role = context.ROLES.Where(r => r.Id == scd.shift.TIMESLIP.RoleId).FirstOrDefault();

                    scd.plateCount = shifts.SelectMany(s => s.ORDERS).Sum(o => o.GuestCount);

                    List<SALE> allSales = shifts.SelectMany(s => s.ORDERS).SelectMany(o => o.SALES).ToList();
                    List<ORDER> allOrders = shifts.SelectMany(s => s.ORDERS).ToList();

                    ///Sales by revenue type.
                    var q1 = allSales.Where(s => !s.IsSeeServer).GroupBy(r => r.RevenueTypeId);
                    if (q1.Any())
                    {
                        foreach (IGrouping<Int64, SALE> grouping in q1)
                        {
                            string rtname = "";
                            long gid = grouping.First().RevenueTypeId;
                            if (gid == 0)
                            {
                                rtname = "N/A";
                            }
                            else
                            {
                                rtname = context.REVENUE_TYPES.Where(rt => rt.Id == gid).First().Name.ToUpper() + ":";
                            }

                            decimal total = grouping.Sum(s => s.ActualPrice * s.CountOrdered);

                            if (total != 0)
                            {
                                scd.totalSales += total;

                                SALES_BY_REVTYPE sbrt = new SALES_BY_REVTYPE();
                                sbrt.rtId = gid;
                                sbrt.rtName = rtname;
                                sbrt.total = total;
                                scd.salesGroupByRevType.Add(sbrt);
                            }
                        }
                    }

                    try
                    {
                        if (isHouseCheckout)
                        {
                            var deposits = context.DEPOSITS.Where(d => d.BUSINESS_DAY.Id == scd.businessDay.Id && d.Amount > 0 && d.Type == null);
                            if (deposits.Any())
                            {
                                scd.dayCashStart = deposits.Sum(a => a.Amount);
                            }
                        }
                    }
                    catch (Exception exe)
                    {
                        Logging.LogException(exe);
                    }

                    ///Sales by comp type.
                    foreach (COMP_ACCOUNT a in context.COMP_ACCOUNTS.Where(t => t.IsComp))
                    {
                        string rtname = a.Name.ToUpper();
                        List<SALE> listOfSales = allSales.Where(s => s.DiscountId == a.Id).ToList();

                        decimal total = 0M;
                        if (listOfSales.Count != 0)
                        {
                            total += listOfSales.Sum(s => s.DiscountRate * s.ActualPrice * s.CountOrdered);
                        }
                        if (total != 0)
                        {
                            scd.totalComps += total;
                            COMPS_BY_COMPTYPE cbct = new COMPS_BY_COMPTYPE();
                            cbct.ctId = a.Id;
                            cbct.ctName = a.Name;
                            cbct.total = total;
                            scd.salesGroupByCompType.Add(cbct);
                        }
                    }

                    ///Sales by void type.
                    foreach (COMP_ACCOUNT a in context.COMP_ACCOUNTS.Where(t => t.IsVoid))
                    {
                        string rtname = a.Name.ToUpper();
                        List<SALE> listOfSales = allSales.Where(s => s.DiscountId == a.Id).ToList();

                        decimal total = 0M;

                        if (listOfSales.Count != 0)
                        {
                            total += listOfSales.Sum(s => s.DiscountRate * s.ActualPrice * s.CountOrdered);
                        }

                        if (total != 0)
                        {
                            scd.totalVoids += total;
                            VOIDS_BY_VOIDTYPE vbvt = new VOIDS_BY_VOIDTYPE();
                            vbvt.vtId = a.Id;
                            vbvt.vtName = a.Name;
                            vbvt.total = total;
                            scd.salesGroupByVoidType.Add(vbvt);
                        }

                    }

                    ///Sales by promo type
                    foreach (COMP_ACCOUNT a in context.COMP_ACCOUNTS.Where(t => (t.IsPromo)))
                    {
                        string rtname = a.Name.ToUpper();
                        List<SALE> listOfSales = allSales.Where(s => s.DiscountId == a.Id).ToList();

                        decimal total = 0M;

                        if (listOfSales.Count != 0)
                        {
                            total += listOfSales.Sum(s => s.DiscountRate * s.ActualPrice * s.CountOrdered);
                        }
                        if (total != 0)
                        {
                            scd.totalPromo += total;

                            PROMOS_BY_PROMOTYPE pbpt = new PROMOS_BY_PROMOTYPE();
                            pbpt.ptName = rtname;
                            pbpt.total = total;
                            pbpt.ptId = a.Id;
                            scd.salesGroupByPromoType.Add(pbpt);
                        }
                    }

                    ///Paid In
                    foreach (PAYMENT_REASON a in context.PAYMENT_REASONS.Where(p => (p.IsPaidIn)))
                    {
                        string rtname = a.Name.ToUpper();
                        List<PAYMENT> listOfpayments = shifts.SelectMany(s => s.PAYMENTS).Where(p => p.WasPaidIn).ToList();

                        decimal total = 0M;

                        if (listOfpayments.Count != 0)
                        {
                            total += listOfpayments.Sum(p => p.Amount);
                        }
                        if (total != 0)
                        {
                            scd.totalPaidIn += total;

                            PAIDIN_BY_TYPE pbpt = new PAIDIN_BY_TYPE();
                            pbpt.name = rtname;
                            pbpt.total = total;
                            pbpt.reasonId = a.Id;
                            scd.paidInByType.Add(pbpt);
                        }
                    }

                    ///Paid Out
                    foreach (PAYMENT_REASON a in context.PAYMENT_REASONS.Where(p => (!p.IsPaidIn)))
                    {
                        string rtname = a.Name.ToUpper();
                        List<PAYMENT> listOfpayments = shifts.SelectMany(s => s.PAYMENTS).Where(p => !p.WasPaidIn).ToList();

                        decimal total = 0M;

                        if (listOfpayments.Count != 0)
                        {
                            total += listOfpayments.Sum(p => p.Amount);
                        }
                        if (total != 0)
                        {
                            scd.totalPaidOut += total;

                            PAIDOUT_BY_TYPE pbpt = new PAIDOUT_BY_TYPE();
                            pbpt.name = rtname;
                            pbpt.total = total;
                            pbpt.reasonId = a.Id;
                            scd.paidOutByType.Add(pbpt);
                        }
                    }

                    ///Gift card sales total (selling giftcards not using giftcard).
                    IEnumerable<GIFT_CARDS_SOLD> gcTransactions = shifts.SelectMany(s => s.ORDERS.SelectMany(o => o.GIFT_CARDS_SOLDS));
                    if (gcTransactions.Any())
                    {
                        scd.giftCardAmountSold = gcTransactions.Sum(g => g.Amount);
                    }

                    ///Exclusive tax total.
                    if (allOrders != null && allOrders.Count != 0)
                    {
                        foreach (ORDER o in allOrders)
                        {
                            decimal exclusivelyTaxable = 0M;
                            decimal total =
                                ORDER.SalesExclusiveTaxTotal(o.SALES.ToList(), out exclusivelyTaxable);
                            scd.exclusivelyTaxableSales += exclusivelyTaxable;
                            scd.totalExclusiveTaxes += total;
                        }
                    }

                    ///Inclusive tax total.
                    var q3 = allSales.
                        Where(s => s.InclusiveTaxRateId != null && !s.WasCompedInEntire && !s.WasVoided)
                        .GroupBy(r => r.InclusiveTaxRateId);
                    if (q3.Any())
                    {
                        foreach (IGrouping<Int64?, SALE> grouping in q3)
                        {
                            long gid = (long)grouping.First().InclusiveTaxRateId;
                            string rtname = context.INCLUSIVE_TAXRATES.Where(tr => tr.Id == gid).First().Name.ToUpper() + ":";
                            decimal incTaxable = 0M;
                            decimal incTax = ORDER.SalesInclusiveTaxTotal(grouping.ToList(), context, out incTaxable);

                            if (incTax > 0)
                            {
                                scd.inclusivelyTaxableSales += incTaxable;
                                scd.totalInclusiveTaxes += incTax;
                                INCLUSIVE_TAX_BY_TAXTYPE itbtt = new INCLUSIVE_TAX_BY_TAXTYPE();
                                itbtt.tId = gid;
                                itbtt.name = rtname;
                                itbtt.incTax = incTax;
                                itbtt.grossSales = incTaxable;
                                itbtt.netSales = incTaxable - incTax;
                                scd.salesGroupByInclusiveType.Add(itbtt);
                            }
                        }
                    }


                    ///Now sift through the transactions by transaction type.
                    var q = shifts.SelectMany(o => o.ORDERS.SelectMany(t => t.TRANSACTIONS).Where(g => g.WasVoided == false))
                        .GroupBy(p => p.TransactionType);
                    if (q.Any())
                    {
                        foreach (IGrouping<int, TRANSACTION> grouping in q)
                        {
                            long type = grouping.First().TransactionType;
                            string groupName = null;

                            switch (type)
                            {
                                case TRANSACTION.CONST_PAY_CASH:
                                    groupName = "Cash:";
                                    var qOtherUsersCash = grouping.Where(t => t.UserId != scd.user.Id);
                                    if (qOtherUsersCash.Any())
                                    {
                                        foreach (TRANSACTION t in qOtherUsersCash)
                                        {
                                            scd.transactionsByAnotherUser.Add(t);
                                        }
                                    }
                                    break;
                                case TRANSACTION.CONST_PAY_CHECK:
                                    groupName = "Check:";
                                    var qOtherUsersCheck = grouping.Where(t => t.UserId != scd.user.Id);
                                    if (qOtherUsersCheck.Any())
                                    {
                                        foreach (TRANSACTION t in qOtherUsersCheck)
                                        {
                                            scd.transactionsByAnotherUser.Add(t);
                                        }
                                    }
                                    break;
                                case TRANSACTION.CONST_PAY_CREDIT:
                                    foreach (Int64 i in grouping.Select(g => g.Id).ToList())
                                    {
                                        scd.ccTransactionIds.Add(i);
                                    }
                                    groupName = "Credit:";
                                    var qOtherUsersCredit = grouping.Where(t => t.UserId != scd.user.Id);
                                    if (qOtherUsersCredit.Any())
                                    {
                                        foreach (TRANSACTION t in qOtherUsersCredit)
                                        {
                                            scd.transactionsByAnotherUser.Add(t);
                                        }
                                    }
                                    scd.creditCardTipTotal += grouping.Sum(g => g.Gratuity);
                                    scd.creditTransactionTotal += grouping.Sum(g => g.Base);
                                    break;
                                case TRANSACTION.CONST_PAY_GIFT:
                                    foreach (Int64 i in grouping.Select(g => g.Id).ToList())
                                    {
                                        scd.gcTransactionIds.Add(i);
                                    }

                                    groupName = "Gift:";
                                    var qOtherUsersGift = grouping.Where(t => t.UserId != scd.user.Id);
                                    if (qOtherUsersGift.Any())
                                    {
                                        foreach (TRANSACTION t in qOtherUsersGift)
                                        {
                                            scd.transactionsByAnotherUser.Add(t);
                                        }
                                    }
                                    scd.giftCardTipTotal += grouping.Sum(g => g.Gratuity);
                                    scd.giftCardTransTotal += grouping.Sum(g => g.Base);
                                    break;
                                case TRANSACTION.CONST_PAY_ACCOUNT:
                                    scd.houseTransactionsTotal += grouping.Sum(g => g.Gratuity + g.Base);
                                    groupName = "House:";
                                    var qOtherUsersHouse = grouping.Where(t => t.UserId != scd.user.Id);
                                    if (qOtherUsersHouse.Any())
                                    {
                                        foreach (TRANSACTION t in qOtherUsersHouse)
                                        {
                                            scd.transactionsByAnotherUser.Add(t);
                                        }
                                    }

                                    ///Now let's break the house payments down by each type.
                                    var qHGroup = grouping.GroupBy(t => t.NavHouseAccountId);
                                    if (qHGroup.Any())
                                    {
                                        foreach (IGrouping<long?, TRANSACTION> hGrouping in qHGroup)
                                        {
                                            HOUSE_ACCOUNT_BY_TYPE habt = new HOUSE_ACCOUNT_BY_TYPE();
                                            habt.accountId = (long)hGrouping.First().TransactionTypeId;
                                            habt.name = context.HOUSE_ACCOUNTS.Where(ha => ha.Id == habt.accountId).First().Name;
                                            habt.total = hGrouping.Sum(t => t.Gratuity + t.Base);
                                            scd.houseAccountByType.Add(habt);
                                        }
                                    }
                                    break;
                            }
                            decimal totalPay = grouping.Sum(g => g.Base + g.Gratuity);
                            scd.paymentTotal += totalPay;
                            TRANSACTIONS_BY_TRANSACTION_TYPE tbtt = new TRANSACTIONS_BY_TRANSACTION_TYPE();
                            tbtt.tTypeId = type;
                            tbtt.name = groupName;
                            tbtt.total = totalPay;
                            scd.transactionsByTypeList.Add(tbtt);
                        }
                    }

                    var ordersQ = shifts.SelectMany(s => s.ORDERS);
                    if (ordersQ.Any())
                    {
                        decimal netSales = (from o in ordersQ select o.RoundedSalesSubtotal).DefaultIfEmpty().Sum();
                        decimal discounts = (scd.totalComps + scd.totalPromo + scd.totalVoids);
                        decimal error = discounts - (scd.totalSales - netSales);
                        scd.totalSales += error;
                    }
                }
            }
            catch (Exception ex)
            {
                Logging.LogException(ex);
            }
            return scd;
        }


        #region Binding Specific
        public string UserDisplayName
        {
            get
            {
                if (User != null)
                {
                    return User.ScreenName;
                }
                else
                {
                    return "";
                }
            }
        }
        public bool RoleChoicesAreLocked
        {
            get { return IsClockedIn; }
        }
        public string ClaimedDrawerString
        {
            get
            {
                if (MyDrawerOwnershipStatus == (int)DrawerOwnershipEnum.NoDrawer)
                {
                    return "";
                }
                else if (MyDrawerOwnershipStatus == (int)DrawerOwnershipEnum.BothDrawers)
                {
                    return "You own both Drawer Locks";
                }
                else if (MyDrawerOwnershipStatus == (int)DrawerOwnershipEnum.Drawer1)
                {
                    return "You own the Drawer 1 Lock";
                }
                else
                {
                    return "You own the Drawer 2 Lock";
                }
            }
        }
        public string CancelButtonTextString
        {
            get
            {
                if (IsClockedIn && !IsOnBreak && UserCanOrder())
                {
                    return "Desktop";
                }
                else
                {
                    return "Lock";
                }
            }
        }
        public Visibility IsClockedInVisible
        {
            get
            {
                if (IsClockedIn)
                {
                    return Visibility.Hidden;
                }
                else
                {
                    return Visibility.Visible;
                }
            }
        }
        public Visibility IsClockedOutVisible
        {
            get
            {
                if (!IsClockedIn || IsOnBreak)
                {
                    return Visibility.Hidden;
                }
                else
                {
                    return Visibility.Visible;
                }
            }
        }
        public Visibility IsStartBreakVisible
        {
            get
            {
                if (!IsOnBreak && IsClockedIn)
                {
                    return Visibility.Visible;
                }
                else
                {
                    return Visibility.Hidden;
                }
            }
        }
        public Visibility IsEndBreakVisible
        {
            get
            {
                if (IsOnBreak && IsClockedIn)
                {
                    return Visibility.Visible;
                }
                else
                {
                    return Visibility.Hidden;
                }
            }
        }

        public Visibility SystemConfigIsVisible
        {
            get
            {
                if (UserIsManager()) return Visibility.Visible;
                else return Visibility.Hidden;
            }
        }
        #endregion
    }
}
